﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Serialize.Linq;
using Serialize.Linq.Extensions;
using System.Runtime.Serialization;
using Serialize.Linq.Serializers;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Json;
using PubSubGeneric.WCFContracts;
using System.ServiceModel;
using PubSubGeneric.WCFContracts.Utils;
namespace PubSubGeneric.WCFSubscriptionClient
{
    public class WCFSubscriptionService : ISubscriptionService, IWCFSubscriber
    {
        IWCFSubscriptionServiceAdapter subscriptionservice;
        MethodInfo PublishMi;
        DuplexChannelFactory<IWCFSubscriptionServiceAdapter> chn;

        public CommunicationState ChannelState
        {
            get
            {
                return chn.State;
            }
        }

        public ISubscriptionCatalog SubscriptionCatalog
        {
            get;
            set;
        }

        public WCFSubscriptionService()
            : this(PubSubManager.Catalog)
        {

        }

        public WCFSubscriptionService(ISubscriptionCatalog subscriptionCatalog)
        {
            this.SubscriptionCatalog = subscriptionCatalog;
            InstanceContext instanceContext = new InstanceContext(this);
            chn = new DuplexChannelFactory<IWCFSubscriptionServiceAdapter>(instanceContext, "PubSubGeneric.ISubscriber");
            subscriptionservice = chn.CreateChannel();

            PublishMi = this.GetType().GetMethod("Publish");
        }

        public void Subscribe<T>(string topic, ISubscriber<T> subscriber)
        {
            Subscribe<T>(topic, subscriber, null);
        }

        public void Subscribe<T>(string topic, ISubscriber<T> subscriber, Expression<Func<T, bool>> predicate)
        {
            subscriptionservice.Subscribe(topic, predicate.ToExpressionNode(), Util.GetFullTypeName<T>());
            this.SubscriptionCatalog.Add(topic, new SubscriptionInfo<T>(subscriber, predicate));
        }

        public void UnSubscribe<T>(string topic, ISubscriber<T> subscriber)
        {
            UnSubscribe(topic, subscriber, null);
        }

        public void UnSubscribe<T>(string topic, ISubscriber<T> subscriber, Expression<Func<T, bool>> predicate)
        {
            subscriptionservice.UnSubscribe(topic, predicate.ToExpressionNode(), Util.GetFullTypeName<T>());
            this.SubscriptionCatalog.Remove(topic, new SubscriptionInfo<T>(subscriber, predicate));
        }

        public void OnTopicPublished(string topicName, string args, string typeName)
        {
            object argobj = WCFSerializer.DeSerialize(args, typeName);

            MethodInfo PublishMiGeneric = PublishMi.MakeGenericMethod(Type.GetType(typeName));
            PublishMiGeneric.Invoke(this, new object[] { topicName, argobj });
        }

        public void Publish<T>(string topic, T args)
        {
            this.SubscriptionCatalog.GetTopicSubscribers<T>(topic, args).First().Subscriber.OnTopicPublished(topic, args);
        }
    
    }
}
